package escalonador;

/**
 * Classe responsavel por executar o algoritmo Round Robin.
 * 
 * @author Barbara Barbosa Silva
 * @author Daniel Tsuha
 * @author Felipe Sa de Mello
 * @author Lucas Machado
 */
public class RoundRobin {

	/**
	 * {@link Escalonador} reponsavel por gerenciar as listas.
	 */
	Escalonador escalonador;

	/**
	 * {@link Processador} responsavel por executar as operacoes
	 */
	Processador processador;

	/**
	 * Variavel responsavel por guardar a quantidade de quanta executados.
	 */
	static int quanta;

	/**
	 * Variavel responsavel por guardar a quantidade de instrucoes executadas.
	 */
	static int instrucoes;

	/**
	 * Contrutor da classe RoundRobin
	 * 
	 * @param escalonador
	 *            {@link Escalonador} usado para manipular os processos.
	 * @param processador
	 *            {@link Processador} usado para efetuar as operacoes.
	 */
	public RoundRobin(Escalonador escalonador, Processador processador) {
		this.escalonador = escalonador;
		this.processador = processador;
		quanta = 0;
	}

	/**
	 * Metodo que calcula a media de troca de processos no processador.
	 * 
	 * @return a media de troca de processos.
	 */
	double mediaTrocas() {
		double i = 0;
		for (BCP processo : escalonador.tabelaProcessos) {
			i += processo.vezesProcessado;
		}
		return i / this.escalonador.tabelaProcessos.size();
	}

	/**
	 * Metodo que calcula a media de instrucoes executadas por quantum.
	 * 
	 * @return a media de instrucoes por quantum.
	 */
	double mediaInstrucoes() {
		return (double) instrucoes / quanta;
	}

	/**
	 * Metodo que executa o algoritmo Round Robin no processador com o
	 * escalonador.
	 */
	public void executar() {
		BCP processo;
		while (!escalonador.processosProntos.isEmpty()
				|| !escalonador.processosBloqueados.isEmpty()) {
			processo = escalonador.processosProntos.poll();
			if (processo != null) {

				if (processo.estado != Util.statusProcesso.BLOQUEADO) {
					Logger.executando(processo);
					processo.estado = Util.statusProcesso.EXECUTANDO;

					Util.statusProcesso retorno = processador.processaBCP(processo);
					quanta++;

					if (retorno == Util.statusProcesso.BLOQUEADO) {
						processo.estado = Util.statusProcesso.BLOQUEADO;
						escalonador.processosBloqueados.add(processo);

					} else if (retorno == Util.statusProcesso.PRONTO) {
						processo.estado = Util.statusProcesso.PRONTO;
						escalonador.processosProntos.add(processo);

					} else if (retorno == Util.statusProcesso.TERMINADO) {
						Logger.terminado(processo);
					}
				}
			}
			escalonador.atualizaListas();
		}
		Logger.mediaTrocas(this.mediaTrocas());
		Logger.mediaInstrucoes(mediaInstrucoes());
		Logger.quantum(processador);
	}
}